#ifndef K_PACKAGE_H
#define K_PACKAGE_H
#pragma once

#include "KAutoPtr.h"
#include <cstdint>
#include <type_traits>

class KPackage {
public:
    enum { DefaultSize = 64 };
public:
    explicit KPackage(size_t size = KPackage::DefaultSize);
    KPackage(const KPackage &other);
public:
    KPackage &operator=(const KPackage &other);
public:
    template <class T>
    typename std::enable_if<std::is_pointer<T>::value, T>::type data() const
    { return reinterpret_cast<T>(m_data.get()); }
    uint8_t *data() const               { return m_data; }
    bool hasData() const                { return m_len > 0; }
    size_t length() const               { return m_len; }
    size_t size() const                 { return m_size; }
    size_t space() const                { return m_size - m_len; }
public:
    KPackage &append(const void *src, size_t len);
    KPackage &append(const KPackage &src);
    template <class T>
    KPackage &append(const T &src)      { return append(&src, sizeof src); }
    template <class T, size_t N>
    KPackage &append(const T (&src)[N]) { return append(src, sizeof src); }
    KPackage &appendNothing(size_t len);
    void clear();
    void fill(uint8_t val = 0);
    bool find(size_t &pos, const void *val, size_t len) const;
    bool qfind(size_t &pos, const void *val, size_t len) const;
    KPackage &rewind(size_t len);
    template <class T>
    KPackage &rewind()                  { return rewind(sizeof(T)); }
    KPackage &rewindTo(size_t len);
    void shrink(size_t beg = 0, bool move = true);
private:
    void resize(size_t size);
private:
    KAutoPtr<uint8_t, true> m_data;
    size_t m_len, m_size;
};

#endif // K_PACKAGE_H